package com.bytesizedhosting.api.android.darthcrap.components.accordian;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.ScrollView;

public final class Accordian extends ScrollView {
	private LinearLayout objRootLayout = null;
	private LayoutInflater objInflater = null;
	private StateContainer objStateContainer = null;
	private ArrayList<AccordianEntry> lstEntries = null;
	
	public Accordian(Context objContext) {
		super(objContext);
		initializeAccordian(objContext);
	}
	
	public Accordian(Context objContext, StateContainer objStateContainer) {
		super(objContext);
		initializeAccordian(objContext, objStateContainer);
	}
	
	public Accordian(Context objContext, AttributeSet setAttributes) {
		super(objContext, setAttributes);
		initializeAccordian(objContext);
	}
	
	public Accordian(Context objContext, AttributeSet setAttributes, StateContainer objStateContainer) {
		super(objContext, setAttributes);
		initializeAccordian(objContext, objStateContainer);
	}
	
	public Accordian(Context objContext, AttributeSet setAttributes, int intDefStyle) {
		super(objContext, setAttributes, intDefStyle);
		initializeAccordian(objContext);
	}
	
	public Accordian(Context objContext, AttributeSet setAttributes, int intDefStyle, StateContainer objStateContainer) {
		super(objContext, setAttributes, intDefStyle);
		initializeAccordian(objContext, objStateContainer);
	}
	
	private void initializeAccordian(Context objContext) {
		initializeAccordian(objContext,null);
	}
	
	private void initializeAccordian(Context objContext, Accordian.StateContainer objStateContainer) {
		this.objInflater = LayoutInflater.from(objContext);
		this.lstEntries = new ArrayList<AccordianEntry>();
		this.setStateContainer(this.objStateContainer);
		
		this.setScrollbarFadingEnabled(false);
		
		this.objRootLayout = new LinearLayout(objContext);
		this.objRootLayout.setOrientation(LinearLayout.VERTICAL);
		this.addView(objRootLayout,new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
	}
	
	public void setStateContainer(Accordian.StateContainer objStateContainer) {
		this.objStateContainer = objStateContainer;
	}
	
	public void holdState() {
		if (this.objStateContainer != null) {
			State objState = new State();
			objState.setScrollPercentage(this.getScrollPercentage());
			for (AccordianEntry objEntry : this.lstEntries) {
				objState.addEntry(objEntry.hashCode(), objEntry.isOpen());
			}
			this.objStateContainer.setState(objState);
		}
	}
	
	public void restoreState() {
		if (this.objStateContainer != null) {
			State objState = this.objStateContainer.getState();
			if (objState != null) {
				Map<Integer,AccordianEntry> mapEntries = new HashMap<Integer,AccordianEntry>();
				Map<Integer,Boolean> mapStates = objState.getMap();
				AccordianEntry objEntry;
				for (AccordianEntry objLoopEntry : this.lstEntries) {
					mapEntries.put(objLoopEntry.hashCode(), objLoopEntry);
				}
				for (Map.Entry<Integer, Boolean> objLoopEntry : mapStates.entrySet()) {
					if ((objEntry = mapEntries.get(objLoopEntry.getKey())) != null) {
						objEntry.setState(objLoopEntry.getValue());
					}
				}
				if (mapEntries.keySet().equals(mapStates.keySet())) {
					this.setScrollPercentage(objState.getScrollPercentage());
				}
			}
		}
	}
	
	public boolean addEntry(AccordianEntry objEntry) {
		if (this.lstEntries.contains(objEntry)) {
			return false;
		}
		else {
			this.lstEntries.add(objEntry);
			objEntry.buildEntry(this.objInflater, this.objRootLayout, this.lstEntries.size() == 1);
			return true;
		}
		
	}
	
	public void setScrollPercentage(final double dblScrollAmount) {
		final Accordian objThis = this;
		this.post(new Runnable() {
			public void run() {
				objThis.invalidate();
		        int intScrollTo = (int) (dblScrollAmount * (objThis.objRootLayout.getHeight() - objThis.getHeight()));
		        objThis.scrollTo(0, intScrollTo);
		        objThis.invalidate();
			}
		});
	}
	
	public double getScrollPercentage() {
		return (double)(this.getScrollY()) / (double)((this.objRootLayout.getHeight() - this.getHeight()));
	}
	
	public static class StateContainer {
		private State objState = null;
		private long lngTimeUpdated = 0;
		private int intDecayTime = 0;
		
		public StateContainer() {
			this(1000);
		}
		
		public StateContainer(int intDecayTime) {
			this.intDecayTime = intDecayTime;
		}
		
		void setState(State objState) {
			this.objState = objState;
			this.lngTimeUpdated = new Date().getTime();
		}
		
		State getState() {
	        if ((new Date().getTime() - this.lngTimeUpdated) > this.intDecayTime) {
	        	return null;
	        }
	        else {
	        	State objStoredState = this.objState;
	        	this.objState = null;
	        	this.lngTimeUpdated = 0;
	        	return objStoredState;
	        }
		}
	}
	
	private static class State {		
		private Map<Integer,Boolean> mapStates = new HashMap<Integer,Boolean>();
		private double dblScrollPercentage = 0;
		
		private void addEntry(int intHashCode, boolean boolIsOpen) {
			this.mapStates.put(intHashCode,boolIsOpen);
		}
		
		private void setScrollPercentage(double dblScrollPercentage) {
			this.dblScrollPercentage = dblScrollPercentage;
		}
		
		private double getScrollPercentage() {
			return this.dblScrollPercentage;
		}
		
		private Map<Integer, Boolean> getMap() {
			return Collections.unmodifiableMap(this.mapStates);
		}
	}
}